package com.webank.maling.analyzer.java.processor;

import com.webank.maling.analyzer.java.context.GraphContext;
import com.webank.maling.base.model.*;
import com.webank.maling.base.util.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * RPC调用关系处理器
 */
@Slf4j
public class RpcProcessor extends BaseProcessor<CtType<?>> {
    
    // Topic常量到Q号的映射
    private final Map<String, String> topicToQMap = new HashMap<>();

    public RpcProcessor(GraphContext graphContext) {
        super(graphContext);
    }

    @Override
    public void process(CtType<?> element) {
        try {
            // 第一步：解析Q号定义（@RmbService注解）
            processRmbServiceDefinitions(element);
            
            // 第二步：解析RPC接口和实现
            processRpcCalls(element);
            
        } catch (Exception e) {
            log.error("Failed to process RPC for type: {}", element.getQualifiedName(), e);
        }
    }


    /**
     * 解析@RmbService注解，建立Topic到Q号的映射
     */
    private void processRmbServiceDefinitions(CtType<?> element) {
        for (CtField<?> field : element.getFields()) {
            for (CtAnnotation<?> annotation : field.getAnnotations()) {
                String annotationName = annotation.getAnnotationType().getQualifiedName();
                if (annotationName.contains("RmbService")|| annotationName.endsWith(".RmbService")) {
                    String serviceId = extractAnnotationValue(annotation, "serviceid");
                    if (serviceId != null) {
                        String topicName = field.getSimpleName();
                        topicToQMap.put(topicName, serviceId);
                        log.info("发现Q号定义: {} -> {}", topicName, serviceId);
                    }
                }
            }
        }
    }

    /**
     * 解析RPC调用
     */
    private void processRpcCalls(CtType<?> element) {
        // 处理@RmbClient接口
        if (hasAnnotation(element, "RmbClient")) {
            processRmbClientCalls(element);
        }
        
        // 处理@RmbController实现
        if (hasAnnotation(element, "RmbController")) {
            processRmbControllerImpl(element);
        }
    }

    /**
     * 处理@RmbClient接口调用
     */
    private void processRmbClientCalls(CtType<?> element) {
        for (CtMethod<?> method : element.getMethods()) {
            for (CtAnnotation<?> annotation : method.getAnnotations()) {
                String annotationName = annotation.getAnnotationType().getQualifiedName();
                if (annotationName.contains("RmbTopic") || annotationName.endsWith(".RmbTopic")) {
                    String topicValue = extractAnnotationValue(annotation, "topic");
                    String qNumber = topicToQMap.get(topicValue);
                    
                    if (qNumber != null) {
                        String transCode = extractAnnotationValue(annotation, "transCode");
                        String topicMode = extractAnnotationValue(annotation, "topicMode");
                        String protocol = extractAnnotationValue(annotation, "protocol");
                        
                        // 创建RPC接口节点
                        RpcInterfaceNode interfaceNode = createRpcInterfaceNode(
                            topicValue, element.getQualifiedName(), method.getSimpleName(),
                                qNumber, protocol, topicMode, transCode, method
                        );
                        
                        // 在图数据库中查找对应的实现
                        RpcImplementationNode implNode = findOrCreateRpcImplementationNode(qNumber, transCode);
                        
                        // 建立调用关系
                        createRpcCallEdge(interfaceNode, implNode);
                    }
                }
            }
        }
    }

    /**
     * 处理@RmbController实现
     */
    private void processRmbControllerImpl(CtType<?> element) {
        for (CtMethod<?> method : element.getMethods()) {
            for (CtAnnotation<?> annotation : method.getAnnotations()) {
                String annotationName = annotation.getAnnotationType().getQualifiedName();
                if (annotationName.contains("RmbTopic") || annotationName.endsWith(".RmbTopic")) {
                    String topicValue = extractAnnotationValue(annotation, "topic");
                    String qNumber = topicToQMap.get(topicValue);
                    
                    if (qNumber != null) {
                        String transCode = extractAnnotationValue(annotation, "transCode");
                        String topicMode = extractAnnotationValue(annotation, "topicMode");
                        String protocol = extractAnnotationValue(annotation, "protocol");
                        
                        // 创建RPC实现节点
                        RpcImplementationNode implNode = createRpcImplementationNode(
                            topicValue, element.getQualifiedName(), method.getSimpleName(),
                                qNumber, protocol, topicMode, transCode, method
                        );

                        log.info("创建RPC实现节点: {} -> {}", topicValue, qNumber);
                    }
                }
            }
        }
    }

    /**
     * 创建节点ID（规范：仅Q；若有transCode则 Q#transCode）。
     */
    private String buildNodeId(String qNumber, String transCode) {
        String key = (transCode == null || transCode.isEmpty()) ? qNumber : (qNumber + "#" + transCode);
        return IdGenerator.generate(IdGenerator.builder().fullQualifiedName(key).isShadow(false).build());
    }

    /**
     * 创建RPC接口节点
     */
    private RpcInterfaceNode createRpcInterfaceNode(String topic, String interfaceName, 
                                                   String methodName, String projectQ, 
                                                   String protocol, String topicMode,
                                                   String transCode,
                                                   CtMethod<?> method) {
        String nodeId = buildNodeId(projectQ, transCode);

        RpcInterfaceNode node = RpcInterfaceNode.builder()
                .id(nodeId)
                .nodeType(NodeType.RPC_INTERFACE)
                .topic(topic)
                .interfaceName(interfaceName)
                .methodName(methodName)
                .projectQ(projectQ)
                .protocol(protocol)
                .topicMode(topicMode)
                .name(methodName)
                .fullName(interfaceName + "#" + methodName)
                .type("rpc_interface")
                .visibility("public")
                .isLibrary(false)
                .lineStart(method.getPosition().getLine())
                .lineEnd(method.getPosition().getEndLine())
                .branchName(config.getBranch())
                .commitStatus("COMMITTED")
                .lastUpdated(LocalDateTime.now())
                .repoId(config.getProjectId())
                .isExternal(false)
                .build();

        node.setContent(method.toString());
        processNode(node);
        
        log.info("创建RPC接口节点: {} -> {} (idKey={}#{})", interfaceName + "#" + methodName, topic, projectQ, transCode);
        return node;
    }

    /**
     * 创建RPC实现节点
     */
    private RpcImplementationNode createRpcImplementationNode(String topic, String className, 
                                                             String methodName, String projectQ,
                                                             String protocol, String topicMode,
                                                             String transCode,
                                                             CtMethod<?> method) {
        String nodeId = buildNodeId(projectQ, transCode);

        RpcImplementationNode node = RpcImplementationNode.builder()
                .id(nodeId)
                .nodeType(NodeType.RPC_IMPLEMENTATION)
                .topic(topic)
                .className(className)
                .methodName(methodName)
                .projectQ(projectQ)
                .protocol(protocol)
                .topicMode(topicMode)
                .name(methodName)
                .fullName(className + "#" + methodName)
                .type("rpc_implementation")
                .visibility("public")
                .isLibrary(false)
                .lineStart(method.getPosition().getLine())
                .lineEnd(method.getPosition().getEndLine())
                .branchName(config.getBranch())
                .commitStatus("COMMITTED")
                .lastUpdated(LocalDateTime.now())
                .repoId(config.getProjectId())
                .isExternal(false)
                .build();

        node.setContent(method.toString());
        processNode(node);
        
        log.info("创建RPC实现节点: {} -> {} (idKey={}#{})", className + "#" + methodName, topic, projectQ, transCode);
        return node;
    }

    /**
     * 查找或创建RPC实现节点（占位）
     */
    private RpcImplementationNode findOrCreateRpcImplementationNode(String qNumber, String transCode) {
        String nodeId = buildNodeId(qNumber, transCode);
        boolean exists = false;
        try {
            exists = nebulaClient.vertexExists(NodeType.RPC_IMPLEMENTATION.getValue(), nodeId);
        } catch (Exception e) {
            log.warn("检查RPC顶点是否存在时出错，将继续创建占位节点。id={}", nodeId, e);
        }
        if (exists) {
            // 返回一个轻量节点占位（不再插入），以便建立边
            return RpcImplementationNode.builder()
                    .id(nodeId)
                    .nodeType(NodeType.RPC_IMPLEMENTATION)
                    .topic(null)
                    .className(null)
                    .methodName(null)
                    .projectQ(qNumber)
                    .protocol(null)
                    .topicMode(null)
                    .name(null)
                    .fullName(null)
                    .type("rpc_implementation")
                    .visibility(null)
                    .isLibrary(null)
                    .lineStart(0)
                    .lineEnd(0)
                    .branchName(null)
                    .commitStatus("COMMITTED")
                    .lastUpdated(LocalDateTime.now())
                    .repoId(null)
                    .isExternal(false)
                    .build();
        }

        log.info("未在图上找到RPC实现顶点，创建占位节点 id={}", nodeId);
        RpcImplementationNode node = RpcImplementationNode.builder()
                .id(nodeId)
                .nodeType(NodeType.RPC_IMPLEMENTATION)
                .topic(null)
                .className("UNKNOWN_CLASS")
                .methodName("UNKNOWN_METHOD")
                .projectQ(qNumber)
                .protocol(null)
                .topicMode(null)
                .name("UNKNOWN_METHOD")
                .fullName("UNKNOWN_CLASS#UNKNOWN_METHOD")
                .type("rpc_implementation")
                .visibility("public")
                .isLibrary(false)
                .lineStart(0)
                .lineEnd(0)
                .branchName(null)
                .commitStatus("COMMITTED")
                .lastUpdated(LocalDateTime.now())
                .repoId(null)
                .isExternal(false)
                .build();

        processNode(node);
        return node;
    }

    /**
     * 创建RPC调用边
     */
    private void createRpcCallEdge(RpcInterfaceNode from, RpcImplementationNode to) {
        Edge edge = Edge.builder()
                .srcId(from.getId())
                .dstId(to.getId())
                .type(EdgeType.RPC_CALLS)
                .lineNumber(from.getLineStart())
                .build();

        processEdge(edge);
        log.info("创建RPC调用边: {} -> {}", from.getFullName(), to.getFullName());
    }

    /**
     * 提取注解值
     */
    private String extractAnnotationValue(CtAnnotation<?> annotation, String key) {
        try {
            Object value = annotation.getValue(key);
            return value != null ? value.toString() : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 检查是否有指定注解
     */
    private boolean hasAnnotation(CtType<?> element, String annotationName) {
        for (CtAnnotation<?> annotation : element.getAnnotations()) {
            String name = annotation.getAnnotationType().getQualifiedName();
            if (annotationName.contains(name) || name.endsWith("." + annotationName)) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected Logger getLogger() {
        return log;
    }
} 